#pragma once
#include "core_function.h"
#include <sys/stat.h>
#include "main.h"
#include "ReadBDF.h"

#include "ReadINP.h"
#include "INP_card.h"
#include "ReadCDB.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#ifdef ENABLE_ODB
#include "ConvertOdb.h"
#endif
#ifdef ENABLE_CGNS
#include "ConvertCgns.h"
#endif
#include <Python.h>
#include <dlfcn.h>

using namespace std;

//2025年5月1日 更新参数
// argv参数为4个:
// 1:-i 或--i 表示下个参数为读取路径
// 2:待转换文件的绝对路径  D:\example.odb
// 3:-o 或--o 表示下一个参数为输出路径
// 4:导出路径  D:\example_folder  转换后文件放在这里，日志放在exe所在路径下的convertlog文件夹，命名规则为时间+输入文件名.log

int main_function(int argc, std::vector<std::string> argv) {
	vector<string> para_list;
	for (int i = 1; i < argc; ++i) {
		string temp = argv[i];
		GeneralMethod::replaceSplash(temp);
		para_list.emplace_back(temp);
	}

	time_t now = time(0);
	tm* local_time = localtime(&now);
	std::cout << "Time:  " << asctime(local_time) << "\n";

	string exeName = argv[0];
	GeneralMethod::replaceSplash(exeName);
	cout << exeName << endl;
	std::string exe_directory = exeName.substr(0, exeName.find_last_of("/")); // 储存exe的上级路径

	// 检查参数
    string input_file_path, output_file_path,input_file_name;
	std::pair<bool, std::vector<std::string>> check = check_arguments(para_list, input_file_path, output_file_path, input_file_name);
	if (!check.first)
	{
		for (string& i : check.second)
		{
			cout << i << endl;
		}
		exit(0);
	}

    string input_file_name_without_suffix = input_file_name.substr(0, input_file_name.find_last_of("."));
    filesystem::path _exe_directory(exe_directory);
    filesystem::path log_folder = _exe_directory / "convertlog";
    if (!filesystem::exists(log_folder))
    {
        try
        {
            filesystem::create_directory(log_folder);
        }
        catch (const std::exception&)
        {
            std::cerr << "Error:An error occurred when creating log folder in the root directory!" << endl;
            return -1;
        }
    }

    //将cout的内容写入到convert.log中
    //std::ofstream convert_log("convert.log", std::ios::out | std::ios::binary);
    //convert_log.imbue(std::locale(""));
    //TeeStreamBuf tee(std::cout.rdbuf(), convert_log.rdbuf());  // 创建一个 TeeStreamBuf 对象，同时连接 cout 和 convert_log 的流缓冲区
    //std::streambuf* oldBuf = std::cout.rdbuf(&tee);        // 将 cout 的流缓冲区替换为 TeeStreamBuf 对象

    int current_year = local_time->tm_year + 1900;
    int current_month = local_time->tm_mon+1;
    int current_day = local_time->tm_mday;
    int current_hour = local_time->tm_hour;
    int current_min = local_time->tm_min;
    int current_sec = local_time->tm_sec;
    string _time;
    _time += to_string(current_year) + "_";
    _time += to_string(current_month) + "_";
    _time += to_string(current_day) + "_";
    _time += to_string(current_hour) + "_";
    _time += to_string(current_min) + "_";
    _time += to_string(current_sec) + "_";
	std::ofstream logFile(log_folder.string()+"/"+ _time+input_file_name_without_suffix+".log");
	if (!logFile.is_open()) {
		std::cerr << "Failed to open log file." << std::endl;
		return 1;
	}
	std::streambuf* originalCoutBuf = std::cout.rdbuf();
	std::streambuf* originalCerrBuf = std::cerr.rdbuf();
	DualStream dualCout(originalCoutBuf, logFile.rdbuf());
	DualStream dualCerr(originalCerrBuf, logFile.rdbuf());
	std::cout.rdbuf(&dualCout);
	std::cerr.rdbuf(&dualCerr);

    string file_name = input_file_name;
    string read_path = input_file_path;
    string save_path = output_file_path;
    filesystem::path current_path = std::filesystem::current_path();

    string upper_filename = file_name;
    GeneralMethod::to_upper(upper_filename);
    string suffix = upper_filename.substr(upper_filename.find_last_of("."));
    if (suffix != ".INP" &&
        suffix != ".BDF" &&
        suffix != ".CDB" &&
        suffix != ".OP2" &&
        suffix != ".ODB" &&
        suffix != ".RST" &&
        suffix != ".CGNS")
    {
        cout << file_name << " The format of current file is not supported yet!" << endl;
        exit(0);
    }

	clock_t sta_finnal, end_finnal;
	sta_finnal = clock();

    std::vector<std::string> suffix_vector(para_list.begin()+2, para_list.end());
#ifdef WIN32

#else
	string sys_path_str = exe_directory;	sys_path_str += ":";
	sys_path_str += (exe_directory + "/lib:");
	sys_path_str += (exe_directory + "/lib/python3.12/site-packages:");
	sys_path_str += (exe_directory + "/lib/python3.12/lib-dynload:");
	sys_path_str += (exe_directory + "/lib/python3.12:");

	const char* version = Py_GetVersion();
	std::cout << "Python版本: " << version << std::endl;
	string home = exe_directory;
	wchar_t* home_wchar = GeneralMethod::char_to_wchar(home.c_str());
	Py_SetPythonHome(home_wchar);
	//Py_Initialize();

#endif

	//PyRun_SimpleString("import sys; sys.executable = '/mnt/convert_code/cmake-build-debug/Release/lib/python3.12'");
    if (suffix == ".BDF") {
    	sys_path_str += (exe_directory + "/lib/python3.12/site-packages-for-meshio:");
    	wchar_t* test = GeneralMethod::char_to_wchar(sys_path_str.c_str());
		Py_SetPath(test);

        ReadBDF_::GetInst()->setReadFilePath(read_path+"/"+ file_name);
        ReadBDF_::GetInst()->setWriteFilePath(save_path);
        ReadBDF_::GetInst()->setExeFilePath(exe_directory);

        ReadBDF_::GetInst()->read_bdf_data();

        ReadBDF_::GetInst()->write_vtk_file();
        //ReadBDF_::GetInst()->write_gmsh_file();
        ReadBDF_::GetInst()->write_gmsh_file_from_vtk();
	}
	else if (suffix == ".INP") {
		sys_path_str += (exe_directory + "/lib/python3.12/site-packages-for-meshio:");
		wchar_t* test = GeneralMethod::char_to_wchar(sys_path_str.c_str());
		Py_SetPath(test);
		ReadINP::GetInstance()->readInpMesh(read_path + "/" + file_name);

        //ReadINP::GetInstance()->write_gmsh_file(exe_directory, read_path + "/" + file_name, save_path);
		std::cout<<"INFO : Start Writing VTK..."<<std::endl;
        ReadINP::GetInstance()->write_vtk_file(exe_directory, read_path + "/" + file_name, save_path);
		std::cout<<"INFO : Writing VTK finished"<<std::endl;
		std::cout<<"INFO : Start Writing GMSH..."<<std::endl;
        ReadINP::GetInstance()->write_gmsh_file_from_vtk(exe_directory, read_path + "/" + file_name, save_path);
		std::cout<<"INFO : Writing GMSH finished"<<std::endl;
	}
	else if (suffix == ".CDB") {
		sys_path_str += (exe_directory + "/lib/python3.12/site-packages-for-meshio:");
		wchar_t* test = GeneralMethod::char_to_wchar(sys_path_str.c_str());
		Py_SetPath(test);
		std::string read_file_path = read_path + "/" + file_name;
        bool res = ReadCDB(exe_directory, read_file_path, save_path);
	}
	else if (suffix == ".OP2") {
		// string first_commd = "chmod +x ";
		// first_commd += (exe_directory+"/Extra_Generate ");
		// system(first_commd.c_str());
		// string command_ ;
		// command_ += (exe_directory+"/Extra_Generate ");
		// command_ +=(read_path+" ");
		// command_ +=(file_name+" ");
		// command_ +=(save_path);
		// system(command_.c_str());
		string first_commd = (exe_directory+"/Extra_Generate");
		cout << "extra generate path: "<<first_commd<<endl;
		// pid_t pid = fork();
		// cout << pid<<endl;
		// if (pid == 0) {
		// 	execlp(first_commd.c_str(), read_path.c_str(), file_name.c_str(),save_path.c_str(), NULL);
		// 	_exit(127);
		// }
		// else if (pid > 0) {
		// 	waitpid(pid, &status, 0);
		// }
		// 创建子进程
		if (chmod(first_commd.c_str(),
              S_IRUSR | S_IWUSR | S_IXUSR |
              S_IRGRP | S_IXGRP |
              S_IXOTH) == 0) {
    	}
		else {
		   perror("chmod失败"); // 输出错误信息
		}
		pid_t pid = fork();

		if (pid == -1) {
			// fork失败
			std::cerr << "创建子进程失败: " << strerror(errno) << std::endl;
			return 1;
		}
		else if (pid == 0) {
			// 这是子进程
			// 将string转换为char*数组
			std::vector<char*> args;
			args.push_back(const_cast<char*>(first_commd.c_str()));
			args.push_back(const_cast<char*>(read_path.c_str()));
			args.push_back(const_cast<char*>(file_name.c_str()));
			args.push_back(const_cast<char*>(save_path.c_str()));
			args.push_back(nullptr);  // 数组必须以nullptr结尾

			if (access(first_commd.c_str(), X_OK) != 0) {
				std::cerr << "权限错误或文件不可执行！" << std::endl;
				//exit(1);
			}
			// 执行程序B
			execv(first_commd.c_str(), args.data());

			// 如果execv返回，说明出错了
			std::cerr << "执行程序失败，错误信息: " << strerror(errno) << std::endl;
			// 常见错误码说明
			switch(errno) {
				case ENOENT:
					std::cerr << "找不到程序文件: " << first_commd << std::endl;
					break;
				case EACCES:
					std::cerr << "权限被拒绝，请检查执行权限" << std::endl;
					break;
				case ENOMEM:
					std::cerr << "内存不足" << std::endl;
					break;
				case E2BIG:
					std::cerr << "参数列表过长" << std::endl;
					break;
				case ETXTBSY:
					std::cerr << "程序文件正在被使用" << std::endl;
					break;
			}
			exit(1);
		}
		else {
			// 这是父进程
			int status;
			// 等待子进程结束
			if (waitpid(pid, &status, 0) == -1) {
				std::cerr << "等待子进程时发生错误: " << strerror(errno) << std::endl;
				return 1;
			}

			if (WIFEXITED(status)) {
				std::cout << "程序B执行完成，退出码: " << WEXITSTATUS(status) << std::endl;
			}
			else if (WIFSIGNALED(status)) {
				std::cout << "程序B被信号" << WTERMSIG(status) << "终止" << std::endl;
			}
			else {
				std::cout << "程序B异常终止" << std::endl;
			}
		}
	}
	else if (suffix == ".ODB") {
#ifdef ENABLE_ODB
		sys_path_str += (exe_directory + "/lib/python3.12/site-packages-for-meshio:");
		wchar_t* test = GeneralMethod::char_to_wchar(sys_path_str.c_str());
		Py_SetPath(test);
        //ConvertOdb::ConvertOdbToFile(filePath, outputDir, 0);
        ConvertOdb::ConvertOdbToFile(read_path + "/" + file_name, save_path, 1);
#endif
	}
	else if (suffix == ".RST") {
#ifdef ENABLE_RST

	// string first_commd = "chmod +x ";
	// first_commd += (exe_directory+"/Extra_Generate ");
	// system(first_commd.c_str());
	// string command_ ;
	// command_ += (exe_directory+"/Extra_Generate ");
	// command_ +=(read_path+" ");
	// command_ +=(file_name+" ");
	// command_ +=(save_path);
	// system(command_.c_str());
	string first_commd = (exe_directory+"/Extra_Generate");
	// pid_t pid = fork();
	// if (pid == 0) {
	// 	execlp(first_commd.c_str(), read_path.c_str(), file_name.c_str(),save_path.c_str(), NULL);
	// 	_exit(127);
	// }
	if (chmod(first_commd.c_str(),
		  S_IRUSR | S_IWUSR | S_IXUSR |
		  S_IRGRP | S_IXGRP |
		  S_IXOTH) == 0) {
		  }
	else {
		perror("chmod失败");
	}

    // 创建子进程
    pid_t pid = fork();

    if (pid == -1) {
        // fork失败
        std::cerr << "创建子进程失败: " << strerror(errno) << std::endl;
        return 1;
    }
    else if (pid == 0) {
        // 这是子进程
        // 将string转换为char*数组
        std::vector<char*> args;
        args.push_back(const_cast<char*>(first_commd.c_str()));
        args.push_back(const_cast<char*>(read_path.c_str()));
        args.push_back(const_cast<char*>(file_name.c_str()));
        args.push_back(const_cast<char*>(save_path.c_str()));
        args.push_back(nullptr);  // 数组必须以nullptr结尾

		if (access(first_commd.c_str(), X_OK) != 0) {
			std::cerr << "权限错误或文件不可执行！" << std::endl;
			//exit(1);
		}
        // 执行程序B
        execv(first_commd.c_str(), args.data());

        // 如果execv返回，说明出错了
        std::cerr << "执行程序失败，错误信息: " << strerror(errno) << std::endl;
        // 常见错误码说明
        switch(errno) {
            case ENOENT:
                std::cerr << "找不到程序文件: " << first_commd << std::endl;
                break;
            case EACCES:
                std::cerr << "权限被拒绝，请检查执行权限" << std::endl;
                break;
            case ENOMEM:
                std::cerr << "内存不足" << std::endl;
                break;
            case E2BIG:
                std::cerr << "参数列表过长" << std::endl;
                break;
            case ETXTBSY:
                std::cerr << "程序文件正在被使用" << std::endl;
                break;
        }
        exit(1);
    }
    else {
        // 这是父进程
        int status;
        // 等待子进程结束
        if (waitpid(pid, &status, 0) == -1) {
            std::cerr << "等待子进程时发生错误: " << strerror(errno) << std::endl;
            return 1;
        }

        if (WIFEXITED(status)) {
            std::cout << "程序B执行完成，退出码: " << WEXITSTATUS(status) << std::endl;
        }
        else if (WIFSIGNALED(status)) {
            std::cout << "程序B被信号" << WTERMSIG(status) << "终止" << std::endl;
        }
        else {
            std::cout << "程序B异常终止" << std::endl;
        }
    }

#endif
	}
	else if (suffix == ".CGNS") {
#ifdef ENABLE_CGNS
		sys_path_str += (exe_directory + "/lib/python3.12/site-packages-for-meshio:");
    	wchar_t* test = GeneralMethod::char_to_wchar(sys_path_str.c_str());
		Py_SetPath(test);
        //ConvertRst::ConvertCgnsToFile(read_path + "/" + file_name, save_path, 0);
        ConvertCgns::ConvertCgnsToFile(read_path + "/" + file_name, save_path, 1);
#endif
	}
    end_finnal = clock();
    cout << "\nConvert finished in: " << double(end_finnal - sta_finnal) / CLOCKS_PER_SEC << "s\n\n";
    //std::cout.rdbuf(oldBuf);  // 恢复 cout 的原始流缓冲区
    //
    //convert_log.close();
    //filesystem::rename(current_path.string() + "\\convert.log", para_list[1] + "\\convert.log");

	// 恢复原始的输出流并关闭日志文件
	std::cout.rdbuf(originalCoutBuf);
	std::cerr.rdbuf(originalCerrBuf);
	logFile.close();

	return 0;
}

std::pair<bool, std::vector<std::string>> check_arguments(std::vector<std::string>& arguments,string& input_file_path, string&output_file_path, string& input_file_name)
{
	std::pair<bool, std::vector<std::string>> res = std::make_pair(false, std::vector<std::string>{});

	//如果没写格式 报错并退出
	if (arguments.size()<2)
	{
		res.second.emplace_back("The number of parameters is incorrect!");
		return res;
	}
	if (!GeneralMethod::has_member(arguments, string("-i")) && !GeneralMethod::has_member(arguments, string("--i")))
	{
		res.second.emplace_back("Error:There is not '-i' in parameters!");
		return res;
	}
	else
	{
		for (int i = 0; i < arguments.size(); i++)
		{
			if (arguments[i] == "--i")
			{
				arguments[i] = "-i";
			}
		}
	}
	if (!GeneralMethod::has_member(arguments, string("-o")) && !GeneralMethod::has_member(arguments, string("--o")))
	{
		res.second.emplace_back("Error:There is not '-o' in parameters!");
		return res;
	}
	else
	{
		for (int i = 0; i < arguments.size(); i++)
		{
			if (arguments[i] == "--o")
			{
				arguments[i] = "-o";
			}
		}
	}

	int i_index = std::distance(arguments.begin(), std::find(arguments.begin(), arguments.end(), "-i"))+1;
	int o_index = std::distance(arguments.begin(), std::find(arguments.begin(), arguments.end(), "-o"))+1;

	filesystem::path origin_file_path(arguments[i_index]);
	if (!filesystem::exists(origin_file_path))
	{
		res.second.emplace_back(origin_file_path.string()+", This path does not exist!");
	}
	input_file_path = arguments[i_index].substr(0, arguments[i_index].find_last_of("/"));
	input_file_name = arguments[i_index].substr(arguments[i_index].find_last_of("/")+1);

	filesystem::path output_path(arguments[o_index]);
	if (!filesystem::exists(output_path))
	{
		res.second.emplace_back(output_path.string() + ", This path does not exist!");
	}
	if (!filesystem::is_directory(output_path))
	{
		res.second.emplace_back(output_path.string() + ", Output path is not a folder!");
	}
	output_file_path = arguments[o_index];

	/*std::set<string> output_type = { "VTK", "GMSH" };
	GeneralMethod::to_upper(arguments[2]);
	if (output_type.find(arguments[2]) == output_type.end()) {
		res.second.emplace_back("The output format is incorrect!");
	}
	if (arguments.size()==4)
	{
		GeneralMethod::to_upper(arguments[3]);
		if (output_type.find(arguments[3]) == output_type.end()) {
			res.second.emplace_back("The output format is incorrect!");
		}
	}*/

	if (res.second.empty())
	{
		return std::make_pair(true, std::vector<std::string>{});
	}
	return res;
};

int ConvertModelData(std::string input_label,std::string input_file,std::string output_label,std::string output_path){
	vector<string> temp_vec;

	int* ptr = reinterpret_cast<int*>(&main_function);
	Dl_info info;

	if (dladdr(ptr, &info) != 0) {
		std::cout << "当前动态库路径: " << info.dli_fname << std::endl;
	} else {
		std::cerr << "错误: " << dlerror() << std::endl;
		return -1;
	}
	temp_vec.push_back(info.dli_fname);
	temp_vec.push_back(input_label);
	temp_vec.push_back(input_file);
	temp_vec.push_back(output_label);
	temp_vec.push_back(output_path);
	int res = main_function(temp_vec.size(),temp_vec);

	return res;
};